package playsManager.domainLogic;

import java.util.*;

import playsManager.*;
import playsManager.database.*;

public class DomainLogic {

	/*
	 * note regarding preconditions and postconditions:
	 * 
	 * preconditions and postconditions in this file
	 * for any function are implied to be the same as
	 * the conditions of the
	 * method in the Database.java file with the same
	 * signature if the conditions
	 * are not specified in this file. 
	 * 
	 */
	
	private static DomainLogic instance;
	
	//class invariant: db is not null
	public Database db;
	
	
	public static DomainLogic GetInstance() throws Exception
	{
		//precondition: same as constructor for Database
		//postcondition: domainlogic instance is returned 
		
		if (instance == null)
			instance = new DomainLogic();
		return instance;
	}
	
	private DomainLogic() throws Exception
	{
		//precondition: same as constructor for Database
		
		this.db = Database.GetInstance();
	}
	
	//Precondition: administrator != null
	//Postcondition: administrator is added to the database
	public void AddAdministrator(Administrator administrator) throws Exception
	{
		db.AddAdministrator(administrator);
	}
	public Administrator GetAdministrator(int id) throws Exception
	{
		return db.GetAdministrator(id);
	}
	public ArrayList<Administrator> GetAllAdministrators() throws Exception
	{
		return db.GetAllAdministrators();
	}
	public String DeleteAdministrator(int idToDelete, int idOfDeleter) throws Exception
	{
		//precondition: idToDelete is the id of an existing administrator, and 
		//				idOfDeleter is the id of the currently signed in admin.
		//postcondition: if the id's are not the same, the appropriate admin is deleted
		//				and null is returned.  if the admins are the same, an error
		//				message is returned and no admins are deleted.
		
		if(idOfDeleter == idToDelete)
		{
			return "you cannot delete yourself.";
		}
		else
		{
			db.DeleteAdministrator(idToDelete);
			return null;
		}
	}
	
	public void AddTheater(Theater theater) throws Exception
	{
		db.AddTheater(theater);
	}
	public Theater GetTheater(int id) throws Exception
	{
		return db.GetTheater(id);
	}
	public ArrayList<Theater> GetAllTheaters() throws Exception
	{
		return db.GetAllTheaters();
	}
	public void DeleteTheater(int id) throws Exception
	{
		db.DeleteTheater(id);
	}
	
	public void AddPlay(Play play) throws Exception
	{
		db.AddPlay(play);
	}
	public Play GetPlay(int id) throws Exception
	{
		return db.GetPlay(id);
	}
	public ArrayList<Play> GetTheaterPlays(int theaterId) throws Exception
	{
		ArrayList<Play> result = new ArrayList<Play>();
		for(Play p : db.GetAllPlays())
			if(p.GetTheaterId() == theaterId)
				result.add(p);
		return result;
	}
	public void DeletePlay(int id) throws Exception
	{
		db.DeletePlay(id);
	}
	
	public AdminLogon LoginAsAdmin(LogonInfo info) throws Exception
	{
		return db.LoginAsAdmin(info);
	}
	public TheaterLogon LoginAsTheater(LogonInfo info) throws Exception
	{
		return db.LoginAsTheater(info);
	}
	
	public ArrayList<Play> GetAllPlays() throws Exception
	{
		return db.GetAllPlays();
	}
	
	public ArrayList<Play> GetPlays
	(
			String playName,
			String theaterLocation,
			Date minDate,
			Date maxDate,
			String genre
		) throws Exception
	{
		//precondition: minDate <= maxDate
		//postcondition: all plays in the database matching criteria
		
		return GetPlays(playName, theaterLocation, minDate == null ? null : minDate.getTime(), maxDate == null ? null : maxDate.getTime(), genre);
	}
	
	//Precondition: if(minDate != null && maxDate != null) minDate < maxDate.
	//Postconditions: if(playName != null) all plays in GetPlays() have name Playname
	//		If(theaterLocation != null) all plays in GetPlays() have location theaterLocation
	//		If(minDate != null) all plays in GetPlays() have date >= minDate
	//		If(maxDate != null) all plays in GetPlays() have date <= maxDate
	//		If(genre != null) all plays in GetPlays() have genre genre
	public ArrayList<Play> GetPlays
		(
			String playName,
			String theaterLocation,
			Long minDate,
			Long maxDate,
			String genre
		) throws Exception
	{
		
		System.outprintln("Play name: "+playName);
		System.out.println("Theater location: "+theaterLocation);
		System.out.println("Minimum date: "+minDate);
		System.out.println("Maximum date: "+maxDate);
		System.out.println("Genre: "+genre);
		
		//precondition
		if(minDate != null && maxDate != null) {
			if(minDate >= maxDate){
				System.out.println("Error: maxDate < minDate");
			}
		}

		//precondition: minDate <= maxDate
		//postcondition: all plays in the database matching criteria are returned
		
		ArrayList<Play> allPlays = GetAllPlays();
		ArrayList<Play> selectedPlays = new ArrayList<Play>();

		//do a case insensitive search
		if(playName != null)
			playName = playName.toLowerCase();
		
		if(theaterLocation != null)
			theaterLocation = theaterLocation.toLowerCase();
		
		if(genre != null)
			genre = genre.toLowerCase();
		
		for(Play p : allPlays)
		{
			if(playName != null && !p.GetName().toLowerCase().startsWith(playName))
				continue;
			
			if(theaterLocation != null && !db.GetTheater(p.GetId()).location.toLowerCase().startsWith(theaterLocation))
				continue;
			
			boolean okay = false;
			
			for(long date : p.GetDates())
			{
				if((minDate == 0 || date >= minDate) && (maxDate == 0 || date <= maxDate))
				{
					okay = true;
					break;
				}
			}
			
			if(!okay)
				continue;
			
			if(genre != null && !p.GetGenre().toLowerCase().startsWith(genre))
				continue;
			
			selectedPlays.add(p);
		}

		//Intermediate conditions:
		//	if(selectedPlays.size() > 0){
		//	if(playName != null) selectedPlays.get(i).name.equals(playName)  
		//		for all i < selectedPlays.size()
		//	If(theaterLocation != null) selectedPlays.get(i).location.equals(theaterLocation) 
		//		for all i < selectedPlays.size()
		//	If(minDate != null) selectedPlays.get(i).Date.after(minDate) 
		//		for all i < selectedPlays.size()
		//	If(maxDate != null) selectedPlays.get(i).Date.before(maxDate) 
		//		for all i < selectedPlays.size()
		//	If(genre != null) selectedPlays.get(i).genre.equals(genre) 
		//		for all i < selectedPlays.size()}

		return selectedPlays;
	}
}
